home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / mawk10.zip / PARSE.Y < prev    next >
Text File  |  1991-10-05  |  35KB  |  1,206 lines

  1.  
  2. /********************************************
  3. parse.y
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the AWK programming language.
  8.  
  9. Mawk is distributed without warranty under the terms of
  10. the GNU General Public License, version 2, 1991.
  11. ********************************************/
  12.  
  13. /* $Log:    parse.y,v $
  14.  * Revision 3.4.1.1  91/09/14  17:23:53  brennan
  15.  * VERSION 1.0
  16.  * 
  17.  * Revision 3.4  91/08/13  06:51:53  brennan
  18.  * VERSION .9994
  19.  * 
  20.  * Revision 3.3  91/06/28  04:17:19  brennan
  21.  * VERSION 0.999
  22.  * 
  23.  * Revision 3.2  91/06/27  08:19:47  brennan
  24.  * bigger page size for main code 
  25.  * bigger loop stacks -- both changes need to handle AWF
  26.  * 
  27.  * Revision 3.1  91/06/07  10:28:00  brennan
  28.  * VERSION 0.995
  29.  * 
  30.  * Revision 2.5  91/06/04  08:17:57  brennan
  31.  * removed 8 sr conflicts with %prec
  32.  *   ID  INC_or_DEC
  33.  *   whether to shift or reduce ID->p_expr
  34.  * diffed the y.output files to make sure parser was really the same
  35.  * 
  36.  * Revision 2.4  91/06/04  06:40:42  brennan
  37.  * put parser table memory in zmalloc pool if using byacc
  38.  * 
  39.  * Revision 2.3  91/06/03  08:14:09  brennan
  40.  * block_or_newline nonterminal is now block_or_separator
  41.  * 
  42.  * Revision 2.2  91/04/29  07:16:49  brennan
  43.  * changes to grammar to make $x++ and $A[3]++ work right
  44.  * 
  45.  * Revision 2.1  91/04/08  08:23:39  brennan
  46.  * VERSION 0.97
  47.  * 
  48. */
  49.  
  50.  
  51. %{
  52. #include <stdio.h>
  53. #include "mawk.h"
  54. #include "code.h"
  55. #include "symtype.h"
  56. #include "memory.h"
  57. #include "bi_funct.h"
  58. #include "bi_vars.h"
  59. #include "jmp.h"
  60. #include "field.h"
  61. #include "files.h"
  62.  
  63.  
  64. /* Bison's use of MSDOS and ours clashes */
  65. #undef   MSDOS
  66.  
  67. extern void  PROTO( eat_nl, (void) ) ;
  68. static void  PROTO( resize_fblock, (FBLOCK *, INST *) ) ;
  69. static void  PROTO( code_array, (SYMTAB *) ) ;
  70. static void  PROTO( code_call_id, (CA_REC *, SYMTAB *) ) ;
  71. static int   PROTO( current_offset, (void) ) ;
  72. static void  PROTO( check_id, (SYMTAB *) ) ;
  73. static void  PROTO( check_array, (SYMTAB *) ) ;
  74. static void  PROTO( field_A2I, (void) ) ;
  75.  
  76. static int scope ;
  77. static FBLOCK *active_funct ;
  78.       /* when scope is SCOPE_FUNCT  */
  79.  
  80. #define  code_address(x)  if( is_local(x) )\
  81.                           { code1(L_PUSHA) ; code1((x)->offset) ; }\
  82.                           else  code2(_PUSHA, (x)->stval.cp) 
  83.  
  84. %}
  85.  
  86. %union{
  87. CELL *cp ;
  88. SYMTAB *stp ;
  89. INST  *start ; /* code starting address */
  90. PF_CP  fp ;  /* ptr to a (print/printf) or (sub/gsub) function */
  91. BI_REC *bip ; /* ptr to info about a builtin */
  92. FBLOCK  *fbp  ; /* ptr to a function block */
  93. ARG2_REC *arg2p ;
  94. CA_REC   *ca_p  ;
  95. int   ival ;
  96. }
  97.  
  98. /*  two tokens to help with errors */
  99. %token   UNEXPECTED   /* unexpected character */
  100. %token   BAD_DECIMAL
  101.  
  102. %token   NL
  103. %token   SEMI_COLON
  104. %token   LBRACE  RBRACE
  105. %token   LBOX     RBOX
  106. %token   COMMA
  107. %token   <ival> IO_OUT    /* > or output pipe */
  108.  
  109. %left   P_OR
  110. %left   P_AND
  111. %right  ASSIGN  ADD_ASG SUB_ASG MUL_ASG DIV_ASG MOD_ASG POW_ASG
  112. %right  QMARK COLON
  113. %left   OR
  114. %left   AND
  115. %left   IN
  116. %left   MATCH  NOT_MATCH
  117. %left   EQ  NEQ  LT LTE  GT  GTE
  118. %left   CAT
  119. %left   GETLINE
  120. %left   PLUS      MINUS  
  121. %left   MUL      DIV    MOD
  122. %left   NOT   UMINUS
  123. %nonassoc   IO_IN PIPE
  124. %right  POW
  125. %left   <ival>   INC_or_DEC
  126. %left   DOLLAR    FIELD  /* last to remove a SR conflict
  127.                                 with getline */
  128. %right  LPAREN   RPAREN     /* removes some SR conflicts */
  129. %token  <cp>  CONSTANT  RE
  130. %token  <stp> ID   
  131. %token  <fbp> FUNCT_ID
  132. %token  <bip> BUILTIN 
  133. %token   <cp>  FIELD 
  134.  
  135. %token  PRINT PRINTF SPLIT MATCH_FUNC SUB GSUB LENGTH
  136. /* keywords */
  137. %token  DO WHILE FOR BREAK CONTINUE IF ELSE  IN
  138. %token  DELETE  BEGIN  END  EXIT NEXT RETURN  FUNCTION
  139.  
  140. %type <start>  block  block_or_separator
  141. %type <start>  statement_list statement mark
  142. %type <start>  pattern  p_pattern
  143. %type <start>  print_statement
  144. %type <ival>   pr_args
  145. %type <arg2p>  arg2  
  146. %type <start>  builtin  
  147. %type <start>  getline_file
  148. %type <start>  lvalue field  fvalue
  149. %type <start>  expr cat_expr p_expr  re_or_expr  sub_back
  150. %type <start>  do_statement  while_statement  for_statement
  151. %type <start>  if_statement if_else_statement
  152. %type <start>  while_front  if_front  for_front
  153. %type <start>  fexpr0 fexpr1
  154. %type <start>  array_loop  array_loop_front
  155. %type <start>  exit_statement  return_statement
  156. %type <ival>   arglist args 
  157. %type <fp>     print   sub_or_gsub
  158. %type <fbp>    funct_start funct_head
  159. %type <ca_p>   call_args ca_front ca_back
  160. %type <ival>   f_arglist f_args
  161.  
  162. %%
  163. /*  productions  */
  164.  
  165. program :       program_block
  166.         |       program  program_block 
  167.         ;
  168.  
  169. program_block :  PA_block
  170.               |  function_def
  171.               |  error block
  172.                  { if (scope == SCOPE_FUNCT)
  173.                    { restore_ids() ; scope = SCOPE_MAIN ; }
  174.                    code_ptr = main_code_ptr ;
  175.                  }
  176.               ;
  177.  
  178. PA_block  :  block 
  179.              { /* this do nothing action removes a vacuous warning
  180.                   from Bison */
  181.              }
  182.  
  183.           |  BEGIN  
  184.                 { 
  185.           if ( ! begin_start )
  186.             begin_start = begin_code_ptr =
  187.             (INST*)zmalloc(PAGE_SZ*sizeof(INST)) ;
  188.         
  189.           main_code_ptr = code_ptr ;
  190.                   code_ptr = begin_code_ptr ; 
  191.                   scope = SCOPE_BEGIN ;
  192.                 }
  193.  
  194.              block
  195.                 { begin_code_ptr = code_ptr ;
  196.                   code_ptr = main_code_ptr ; 
  197.                   scope = SCOPE_MAIN ;
  198.                 }
  199.  
  200.           |  END    
  201.                 { 
  202.           if ( ! end_start )
  203.             end_start = end_code_ptr =
  204.             (INST*)zmalloc(PAGE_SZ*sizeof(INST)) ;
  205.         
  206.           main_code_ptr = code_ptr ;
  207.                   code_ptr = end_code_ptr ; 
  208.                   scope = SCOPE_END ;
  209.                 }
  210.  
  211.              block
  212.                 { end_code_ptr = code_ptr ;
  213.                   code_ptr = main_code_ptr ; 
  214.                   scope = SCOPE_MAIN ;
  215.                 }
  216.  
  217.           |  pattern  /* this works just like an if statement */
  218.              { code_jmp(_JZ, (INST*)0, $1) ; }
  219.  
  220.              block_or_separator
  221.              { patch_jmp( code_ptr ) ; }
  222.  
  223.     /* range pattern, see comment in execute.c near _RANGE */
  224.           |  pattern COMMA 
  225.              { code_push($1, code_ptr - $1) ;
  226.                code_ptr = $1 ;
  227.                code1(_RANGE) ; code1(1) ;
  228.                code_ptr += 3 ;
  229.                code_ptr += code_pop(code_ptr) ;
  230.                code1(_STOP0) ;
  231.                $1[2].op = code_ptr - ($1+1) ;
  232.              }
  233.              pattern
  234.              { code1(_STOP0) ; }
  235.  
  236.              block_or_separator
  237.              { $1[3].op = $6 - ($1+1) ;
  238.                $1[4].op = code_ptr - ($1+1) ;
  239.              }
  240.           ;
  241.  
  242. pattern :  expr       %prec  LPAREN
  243.         |  p_pattern
  244.  
  245. /*  these work just like short circuit booleans */
  246.         |  pattern P_OR  
  247.                 { code1(_DUP) ;
  248.                   code_jmp(_JNZ, (INST*)0, (INST*)0) ;
  249.                   code1(_POP) ;
  250.                 }
  251.                 pattern
  252.                 { patch_jmp(code_ptr) ; }
  253.  
  254.         |  pattern P_AND
  255.                 { code1(_DUP) ;
  256.                   code_jmp(_JZ, (INST*)0, (INST*)0) ;
  257.                   code1(_POP) ;
  258.                 }
  259.                 pattern
  260.                 { patch_jmp(code_ptr) ; }
  261.         ;
  262.  
  263. /* we want the not (!) operator to apply to expr if possible
  264.    and then to a pattern.  Two types of pattern do it */
  265.  
  266. p_pattern  :  RE
  267.               { $$ = code_ptr ;
  268.                 code2(_PUSHI, &field[0]) ;
  269.                 code2(_PUSHC, $1) ;
  270.                 code1(_MATCH) ;
  271.               }
  272.  
  273.            |  LPAREN  pattern RPAREN
  274.               { $$ = $2 ; }
  275.            |  NOT  p_pattern
  276.               { code1(_NOT) ; $$ = $2 ; }
  277.            ;
  278.  
  279.  
  280. block   :  LBRACE   statement_list  RBRACE
  281.             { $$ = $2 ; }
  282.         |  LBRACE   error  RBRACE 
  283.             { $$ = code_ptr ; /* does nothing won't be executed */
  284.               print_flag = getline_flag = paren_cnt = 0 ;
  285.               yyerrok ; }
  286.         ;
  287.  
  288. block_or_separator  :  block
  289.                   |  separator     /* default print action */
  290.                      { $$ = code_ptr ;
  291.                        code1(_PUSHINT) ; code1(0) ;
  292.                        code2(_PRINT, bi_print) ;
  293.                      }
  294.  
  295. statement_list :  statement
  296.         |  statement_list   statement
  297.         ;
  298.  
  299.  
  300. statement :  block
  301.           |  expr   separator
  302.              { code1(_POP) ; }
  303.           |  /* empty */  separator
  304.              { $$ = code_ptr ; }
  305.           |  error  separator
  306.               { $$ = code_ptr ;
  307.                 print_flag = getline_flag = 0 ;
  308.                 paren_cnt = 0 ;
  309.                 yyerrok ;
  310.               }
  311.           |  print_statement
  312.           |  if_statement
  313.           |  if_else_statement
  314.           |  do_statement
  315.           |  while_statement
  316.           |  for_statement
  317.           |  array_loop
  318.           |  BREAK  separator
  319.              { $$ = code_ptr ; BC_insert('B', code_ptr) ;
  320.                code2(_JMP, 0) /* don't use code_jmp ! */ ; }
  321.           |  CONTINUE  separator
  322.              { $$ = code_ptr ; BC_insert('C', code_ptr) ;
  323.                code2(_JMP, 0) ; }
  324.           |  exit_statement
  325.           |  return_statement
  326.              { if ( scope != SCOPE_FUNCT )
  327.                      compile_error("return outside function body") ;
  328.              }
  329.           |  NEXT  separator
  330.               { if ( scope != SCOPE_MAIN )
  331.                    compile_error( "improper use of next" ) ;
  332.                 $$ = code_ptr ; code1(_NEXT) ;
  333.               }
  334.           ;
  335.  
  336. separator  :  NL | SEMI_COLON
  337.            ;
  338.  
  339. expr  :   cat_expr
  340.       |   lvalue   ASSIGN   expr { code1(_ASSIGN) ; }
  341.       |   lvalue   ADD_ASG  expr { code1(_ADD_ASG) ; }
  342.       |   lvalue   SUB_ASG  expr { code1(_SUB_ASG) ; }
  343.       |   lvalue   MUL_ASG  expr { code1(_MUL_ASG) ; }
  344.       |   lvalue   DIV_ASG  expr { code1(_DIV_ASG) ; }
  345.       |   lvalue   MOD_ASG  expr { code1(_MOD_ASG) ; }
  346.       |   lvalue   POW_ASG  expr { code1(_POW_ASG) ; }
  347.       |   expr EQ expr  { code1(_EQ) ; }
  348.       |   expr NEQ expr { code1(_NEQ) ; }
  349.       |   expr LT expr { code1(_LT) ; }
  350.       |   expr LTE expr { code1(_LTE) ; }
  351.       |   expr GT expr { code1(_GT) ; }
  352.       |   expr GTE expr { code1(_GTE) ; }
  353.       |   expr MATCH re_or_expr
  354.           { code1(_MATCH) ; }
  355.       |   expr NOT_MATCH  re_or_expr
  356.           { code1(_MATCH) ; code1(_NOT) ; }
  357.  
  358. /* short circuit boolean evaluation */
  359.       |   expr  OR
  360.               { code1(_DUP) ;
  361.                 code_jmp(_JNZ, (INST*)0, (INST*)0) ;
  362.                 code1(_POP) ;
  363.               }
  364.           expr
  365.           { patch_jmp(code_ptr) ; code1(_TEST) ; }
  366.  
  367.       |   expr AND
  368.               { code1(_DUP) ; code_jmp(_JZ, (INST*)0, (INST*)0) ;
  369.                 code1(_POP) ; }
  370.           expr
  371.               { patch_jmp(code_ptr) ; code1(_TEST) ; }
  372.  
  373.       |  expr QMARK  { code_jmp(_JZ, (INST*)0, $1) ; }
  374.          expr COLON  { code_jmp(_JMP, (INST*)0, (INST*)0) ; }
  375.          expr
  376.          { patch_jmp(code_ptr) ; patch_jmp($7) ; }
  377.       ;
  378.  
  379. cat_expr :  p_expr             %prec CAT
  380.          |  cat_expr  p_expr   %prec CAT 
  381.             { code1(_CAT) ; }
  382.          ;
  383.  
  384. p_expr  :   CONSTANT
  385.           {  $$ = code_ptr ; code2(_PUSHC, $1) ; }
  386.       |   ID   %prec AND /* anything less than IN */
  387.           { check_id($1) ;
  388.             $$ = code_ptr ;
  389.             if ( is_local($1) )
  390.             { code1(L_PUSHI) ; code1($1->offset) ; }
  391.             else code2(_PUSHI, $1->stval.cp) ;
  392.           }
  393.                             
  394.       |   LPAREN   expr  RPAREN
  395.           { $$ = $2 ; }
  396.       ;
  397. p_expr  :   p_expr  PLUS   p_expr { code1(_ADD) ; } 
  398.       |   p_expr MINUS  p_expr { code1(_SUB) ; }
  399.       |   p_expr  MUL   p_expr { code1(_MUL) ; }
  400.       |   p_expr  DIV  p_expr { code1(_DIV) ; }
  401.       |   p_expr  MOD  p_expr { code1(_MOD) ; }
  402.       |   p_expr  POW  p_expr { code1(_POW) ; }
  403.       |   NOT  p_expr  
  404.                 { $$ = $2 ; code1(_NOT) ; }
  405.       |   PLUS p_expr  %prec  UMINUS
  406.                 { $$ = $2 ; code1(_UPLUS) ; }
  407.       |   MINUS p_expr %prec  UMINUS
  408.                 { $$ = $2 ; code1(_UMINUS) ; }
  409.       |   builtin
  410.       ;
  411.  
  412. p_expr  :  ID  INC_or_DEC
  413.            { check_id($1) ;
  414.              $$ = code_ptr ;
  415.              code_address($1) ;
  416.  
  417.              if ( $2 == '+' )  code1(_POST_INC) ;
  418.              else  code1(_POST_DEC) ;
  419.            }
  420.         |  INC_or_DEC  lvalue
  421.             { $$ = $2 ; 
  422.               if ( $1 == '+' ) code1(_PRE_INC) ;
  423.               else  code1(_PRE_DEC) ;
  424.             }
  425.         ;
  426.  
  427. p_expr  :  field  INC_or_DEC   
  428.            { if ($2 == '+' ) code1(F_POST_INC ) ; 
  429.              else  code1(F_POST_DEC) ;
  430.            }
  431.         |  INC_or_DEC  field
  432.            { $$ = $2 ; 
  433.              if ( $1 == '+' ) code1(F_PRE_INC) ;
  434.              else  code1( F_PRE_DEC) ; 
  435.            }
  436.         ;
  437.  
  438. lvalue :  ID
  439.         { $$ = code_ptr ; 
  440.           check_id($1) ;
  441.           code_address($1) ;
  442.         }
  443.        ;
  444.  
  445.  
  446. arglist :  /* empty */
  447.             { $$ = 0 ; }
  448.         |  args
  449.         ;
  450.  
  451. args    :  expr        %prec  LPAREN
  452.             { $$ = 1 ; }
  453.         |  args  COMMA  expr
  454.             { $$ = $1 + 1 ; }
  455.         ;
  456.  
  457. builtin :
  458.         BUILTIN mark  LPAREN  arglist RPAREN
  459.         { BI_REC *p = $1 ;
  460.           $$ = $2 ;
  461.           if ( p-> min_args > $4 || p->max_args < $4 )
  462.             compile_error(
  463.             "wrong number of arguments in call to %s" ,
  464.             p->name ) ;
  465.           if ( p->min_args != p->max_args ) /* variable args */
  466.           { code1(_PUSHINT) ;  code1($4) ; }
  467.           code2(_BUILTIN , p->fp) ;
  468.         }
  469.         ;
  470.  
  471. /* an empty production to store the code_ptr */
  472. mark : /* empty */
  473.          { $$ = code_ptr ; }
  474.  
  475. print_statement : print mark pr_args pr_direction separator
  476.             { code2(_PRINT, $1) ; $$ = $2 ;
  477.               if ( $1 == bi_printf && $3 == 0 )
  478.                     compile_error("no arguments in call to printf") ;
  479.               print_flag = 0 ;
  480.               $$ = $2 ;
  481.             }
  482.             ;
  483.  
  484. print   :  PRINT  { $$ = bi_print ; print_flag = 1 ;}
  485.         |  PRINTF { $$ = bi_printf ; print_flag = 1 ; }
  486.         ;
  487.  
  488. pr_args :  arglist { code1(_PUSHINT) ; code1($1) ; }
  489.         |  LPAREN  arg2 RPAREN
  490.            { $$ = $2->cnt ; zfree($2,sizeof(ARG2_REC)) ; 
  491.              code1(_PUSHINT) ; code1($$) ; 
  492.            }
  493.         ;
  494.  
  495. arg2   :   expr  COMMA  expr
  496.            { $$ = (ARG2_REC*) zmalloc(sizeof(ARG2_REC)) ;
  497.              $$->start = $1 ;
  498.              $$->cnt = 2 ;
  499.            }
  500.         |   arg2 COMMA  expr
  501.             { $$ = $1 ; $$->cnt++ ; }
  502.         ;
  503.  
  504. pr_direction : /* empty */
  505.              |  IO_OUT  expr
  506.                 { code1(_PUSHINT) ; code1($1) ; }
  507.              ;
  508.  
  509.  
  510. /*  IF and IF-ELSE */
  511.  
  512. if_front :  IF LPAREN expr RPAREN
  513.             {  $$ = $3 ; eat_nl() ;
  514.            code_jmp(_JZ, (INST*)0, $3) ;
  515.         }
  516.          ;
  517.  
  518. if_statement : if_front statement
  519.                 { patch_jmp( code_ptr ) ;  }
  520.               ;
  521.  
  522. else    :  ELSE { eat_nl() ; code_jmp(_JMP, (INST*)0, (INST*)0) ; }
  523.         ;
  524.  
  525. if_else_statement :  if_front statement else statement
  526.                 { patch_jmp(code_ptr) ; patch_jmp($4) ; }
  527.  
  528.  
  529. /*  LOOPS   */
  530.  
  531. do      :  DO
  532.         { eat_nl() ; BC_new() ; }
  533.         ;
  534.  
  535. do_statement : do statement WHILE LPAREN expr RPAREN separator
  536.         { $$ = $2 ;
  537.           code_jmp(_JNZ, $2, $5) ; 
  538.           BC_clear(code_ptr, $5) ; }
  539.         ;
  540.  
  541. while_front :  WHILE LPAREN expr RPAREN
  542.                 { eat_nl() ; BC_new() ;
  543.                   code_push($3, code_ptr-$3) ;
  544.                   code_ptr = $$ = $3 ;
  545.                   code_jmp(_JMP,(INST*)0, (INST*)0) ;
  546.                 }
  547.             ;
  548.  
  549. while_statement :  while_front  statement
  550.                 { INST *c_addr = code_ptr ; /*continue address*/
  551.           unsigned len ;
  552.  
  553.                   patch_jmp( c_addr) ;
  554.           len = code_pop(c_addr) ;
  555.                   code_ptr += len ;
  556.                   code_jmp(_JNZ, $2, code_ptr-len) ;
  557.                   BC_clear(code_ptr, c_addr) ;
  558.                 }
  559.                 ;
  560.  
  561. for_front  :  FOR LPAREN fexpr0 SEMI_COLON 
  562.                          fexpr1 SEMI_COLON  fexpr0 RPAREN
  563.  
  564.               { $$ = $3 ; eat_nl() ; BC_new() ;
  565.                 /* push fexpr2 and 3 */
  566.                 code_push( $5, $7-$5) ;
  567.                 code_push( $7, code_ptr - $7) ;
  568.                 /* reset code_ptr */
  569.                 code_ptr = $5 ;
  570.                 code_jmp(_JMP, (INST*)0, (INST*)0) ;
  571.               }
  572.            ;
  573.  
  574. for_statement  :  for_front  statement
  575.               { INST *c_addr = code_ptr ;
  576.                 unsigned len = code_pop(code_ptr) ;
  577.  
  578.                 code_ptr += len ;
  579.                 patch_jmp(code_ptr) ;
  580.                 len = code_pop(code_ptr) ;
  581.                 code_ptr += len ;
  582.                 code_jmp(_JNZ, $2, code_ptr-len) ;
  583.                 BC_clear( code_ptr, c_addr) ;
  584.               }
  585.               ;
  586.  
  587. fexpr0  :  /* empty */   { $$ = code_ptr; }
  588.         |  expr   { code1(_POP) ; }
  589.         ;
  590.  
  591. fexpr1  :  /*  empty */
  592.             { /* this will be wiped out when the jmp is coded */
  593.               $$ = code_ptr ; code2(_PUSHC, &cell_one) ; }
  594.         |   expr
  595.         ;
  596.  
  597. /* arrays  */
  598.  
  599. expr    :  expr IN  ID
  600.            { check_array($3) ;
  601.              code_array($3) ; 
  602.              code1(A_TEST) ; 
  603.             }
  604.         |  LPAREN arg2 RPAREN IN ID
  605.            { $$ = $2->start ;
  606.              code1(A_CAT) ; code1($2->cnt) ;
  607.              zfree($2, sizeof(ARG2_REC)) ;
  608.  
  609.              check_array($5) ;
  610.              code_array($5) ;
  611.              code1(A_TEST) ;
  612.            }
  613.         ;
  614.  
  615. lvalue  :  ID mark LBOX  args  RBOX
  616.            { 
  617.              if ( $4 > 1 )
  618.              { code1(A_CAT) ; code1($4) ; }
  619.  
  620.              check_array($1) ;
  621.              if( is_local($1) )
  622.              { code1(LAE_PUSHA) ; code1($1->offset) ; }
  623.              else code2(AE_PUSHA, $1->stval.array) ;
  624.              $$ = $2 ;
  625.            }
  626.         ;
  627.  
  628. p_expr  :  ID mark LBOX  args  RBOX   %prec  AND
  629.            { 
  630.              if ( $4 > 1 )
  631.              { code1(A_CAT) ; code1($4) ; }
  632.  
  633.              check_array($1) ;
  634.              if( is_local($1) )
  635.              { code1(LAE_PUSHI) ; code1($1->offset) ; }
  636.              else code2(AE_PUSHI, $1->stval.array) ;
  637.              $$ = $2 ;
  638.            }
  639.  
  640.         |  ID mark LBOX  args  RBOX  INC_or_DEC
  641.            { 
  642.              if ( $4 > 1 )
  643.              { code1(A_CAT) ; code1($4) ; }
  644.  
  645.              check_array($1) ;
  646.              if( is_local($1) )
  647.              { code1(LAE_PUSHA) ; code1($1->offset) ; }
  648.              else code2(AE_PUSHA, $1->stval.array) ;
  649.              if ( $6 == '+' )  code1(_POST_INC) ;
  650.              else  code1(_POST_DEC) ;
  651.  
  652.              $$ = $2 ;
  653.            }
  654.         ;
  655.  
  656. /* delete A[i] */
  657. statement :  DELETE  ID mark LBOX args RBOX separator
  658.              { 
  659.                $$ = $3 ;
  660.                if ( $5 > 1 ) { code1(A_CAT) ; code1($5) ; }
  661.                check_array($2) ;
  662.                code_array($2) ;
  663.                code1(A_DEL) ;
  664.              }
  665.  
  666.           ;
  667.  
  668. /*  for ( i in A )  statement */
  669.  
  670. array_loop_front :  FOR LPAREN ID IN ID RPAREN
  671.                     { eat_nl() ; BC_new() ;
  672.                       $$ = code_ptr ;
  673.  
  674.                       check_id($3) ;
  675.                       code_address($3) ;
  676.                       check_array($5) ;
  677.                       code_array($5) ;
  678.                       code1(A_LOOP) ; code1(_STOP) ;
  679.                       code1(0) ; /* put offset of following code here*/
  680.                     }
  681.                  ;
  682.  
  683. array_loop :  array_loop_front  statement
  684.               { code1(_STOP) ;  
  685.                 BC_clear( $2 - 2, code_ptr-1) ;
  686.                 $2[-1].op = code_ptr - & $2[-2] ;
  687.               }
  688.            ;
  689.  
  690. /*  fields   
  691.     -- most of this is to get $x++ and $x[5]++ etc
  692.     -- to work right
  693.     (I think the precedence is wrong ++ should be greater than $
  694.     but it is not so here goes ...
  695. */
  696.  
  697. field   :  FIELD
  698.            { $$ = code_ptr ; code2(F_PUSHA, $1) ; }
  699.         |  DOLLAR  ID
  700.            { check_id($2) ;
  701.              $$ = code_ptr ;
  702.              if ( is_local($2) )
  703.              { code1(L_PUSHI) ; code1($2->offset) ; }
  704.              else code2(_PUSHI, $2->stval.cp) ;
  705.              code1(FE_PUSHA) ;
  706.            }
  707.         |  DOLLAR  ID mark LBOX  args RBOX
  708.            { 
  709.              if ( $5 > 1 )
  710.              { code1(A_CAT) ; code1($5) ; }
  711.  
  712.              check_array($2) ;
  713.              if( is_local($2) )
  714.              { code1(LAE_PUSHI) ; code1($2->offset) ; }
  715.              else code2(AE_PUSHI, $2->stval.array) ;
  716.              code1(FE_PUSHA) ;
  717.  
  718.              $$ = $3 ;
  719.            }
  720.         |  DOLLAR LPAREN  expr RPAREN
  721.            { $$ = $3 ;  code1(FE_PUSHA) ; }
  722.         |  DOLLAR  field
  723.            { $$ = $2 ;  field_A2I() ; code1(FE_PUSHA) ; }
  724.         |  LPAREN  field  RPAREN
  725.            { $$ = $2 ; }
  726.         |  DOLLAR  CONSTANT  /* $ "2" */
  727.            { $$ = code_ptr ;
  728.              code2(_PUSHC, $2) ;
  729.              code1(FE_PUSHA) ;
  730.            }
  731.         ;
  732.  
  733. p_expr   :  field   %prec CAT /* removes field (++|--) sr conflict */
  734.             { field_A2I() ; }
  735.         ;
  736.  
  737. expr    :  field   ASSIGN   expr { code1(F_ASSIGN) ; }
  738.         |  field   ADD_ASG  expr { code1(F_ADD_ASG) ; }
  739.         |  field   SUB_ASG  expr { code1(F_SUB_ASG) ; }
  740.         |  field   MUL_ASG  expr { code1(F_MUL_ASG) ; }
  741.         |  field   DIV_ASG  expr { code1(F_DIV_ASG) ; }
  742.         |  field   MOD_ASG  expr { code1(F_MOD_ASG) ; }
  743.         |  field   POW_ASG  expr { code1(F_POW_ASG) ; }
  744.         ;
  745.  
  746. /* split is handled different than a builtin because
  747.    it takes an array and optionally a regular expression as args */
  748.  
  749. p_expr :  SPLIT LPAREN expr COMMA  ID RPAREN
  750.              { $$ = $3 ;
  751.                check_array($5) ;
  752.                code_array($5) ;
  753.                code2(_PUSHI, &fs_shadow) ;
  754.                code2(_BUILTIN, bi_split) ;
  755.              }
  756.           |  SPLIT LPAREN expr COMMA ID COMMA
  757.                { check_array($5) ; code_array($5) ; }
  758.              split_back
  759.              { $$ = $3 ; code2(_BUILTIN, bi_split) ; }
  760.           ;
  761.  
  762. /* split back is not the same as
  763.    re_or_expr RPAREN
  764.    because the action is cast_for_split() instead
  765.    of cast_to_RE()
  766. */
  767.  
  768. split_back :  expr RPAREN
  769.              { 
  770.                if ( code_ptr[-2].op == _PUSHC &&
  771.                    ((CELL *)code_ptr[-1].ptr)->type == C_STRING )
  772.                    cast_for_split(code_ptr[-1].ptr) ;
  773.              }
  774.  
  775.            |  RE  RPAREN
  776.              { code2(_PUSHC, $1) ; }
  777.            ;
  778.  
  779.  
  780.              
  781.  
  782. /*  match(expr, RE) */
  783.  
  784. p_expr : MATCH_FUNC LPAREN expr COMMA re_or_expr RPAREN
  785.         { $$ = $3 ; code2(_BUILTIN, bi_match) ; }
  786.      ;
  787.  
  788. re_or_expr  :   RE
  789.                 { $$ = code_ptr ;
  790.                   code2(_PUSHC, $1) ;
  791.                 }
  792.             |   expr    %prec  MATCH
  793.                 { if ( code_ptr[-2].op == _PUSHC &&
  794.                        ((CELL *)code_ptr[-1].ptr)->type == C_STRING )
  795.                      /* re compile now */
  796.                      cast_to_RE((CELL *) code_ptr[-1].ptr) ;
  797.                 }
  798.             ;
  799.  
  800. /* length w/o an argument */
  801.  
  802. p_expr :  LENGTH
  803.           { $$ = code_ptr ;
  804.             code2(_PUSHI, field) ;
  805.             code2(_BUILTIN, bi_length) ;
  806.           }
  807.        ;
  808.  
  809. exit_statement :  EXIT   separator
  810.                     { $$ = code_ptr ;
  811.                       code1(_EXIT0) ; }
  812.                |  EXIT   expr  separator
  813.                     { $$ = $2 ; code1(_EXIT) ; }
  814.  
  815. return_statement :  RETURN   separator
  816.                     { $$ = code_ptr ;
  817.                       code1(_RET0) ; }
  818.                |  RETURN   expr  separator
  819.                     { $$ = $2 ; code1(_RET) ; }
  820.  
  821. /* getline */
  822.  
  823. p_expr :  getline      %prec  GETLINE
  824.           { $$ = code_ptr ;
  825.             code2(F_PUSHA, &field[0]) ;
  826.             code1(_PUSHINT) ; code1(0) ; 
  827.             code2(_BUILTIN, bi_getline) ;
  828.             getline_flag = 0 ;
  829.           }
  830.        |  getline  fvalue     %prec  GETLINE
  831.           { $$ = $2 ;
  832.             code1(_PUSHINT) ; code1(0) ;
  833.             code2(_BUILTIN, bi_getline) ;
  834.             getline_flag = 0 ;
  835.           }
  836.        |  getline_file  p_expr    %prec IO_IN
  837.           { code1(_PUSHINT) ; code1(F_IN) ;
  838.             code2(_BUILTIN, bi_getline) ;
  839.             /* getline_flag already off in yylex() */
  840.           }
  841.        |  p_expr PIPE GETLINE  
  842.           { code2(F_PUSHA, &field[0]) ;
  843.             code1(_PUSHINT) ; code1(PIPE_IN) ;
  844.             code2(_BUILTIN, bi_getline) ;
  845.           }
  846.        |  p_expr PIPE GETLINE   fvalue
  847.           { 
  848.             code1(_PUSHINT) ; code1(PIPE_IN) ;
  849.             code2(_BUILTIN, bi_getline) ;
  850.           }
  851.        ;
  852.  
  853. getline :   GETLINE  { getline_flag = 1 ; }
  854.  
  855. fvalue  :   lvalue  |  field  ;
  856.  
  857. getline_file  :  getline  IO_IN
  858.                  { $$ = code_ptr ;
  859.                    code2(F_PUSHA, field+0) ;
  860.                  }
  861.               |  getline fvalue IO_IN
  862.                  { $$ = $2 ; }
  863.               ;
  864.  
  865. /*==========================================
  866.     sub and gsub  
  867.   ==========================================*/
  868.  
  869. p_expr  :  sub_or_gsub LPAREN re_or_expr COMMA  expr  sub_back
  870.            {
  871.              if ( $6 - $5 == 2   &&
  872.                   $5->op == _PUSHC  &&
  873.                   ((CELL *) $5[1].ptr)->type == C_STRING )
  874.              /* cast from STRING to REPL at compile time */
  875.                  cast_to_REPL( (CELL *) $5[1].ptr ) ;
  876.  
  877.              code2(_BUILTIN, $1) ;
  878.              $$ = $3 ;
  879.            }
  880.  
  881. sub_or_gsub :  SUB  { $$ = bi_sub ; }
  882.             |  GSUB { $$ = bi_gsub ; }
  883.             ;
  884.  
  885. sub_back    :   RPAREN    /* substitute into $0  */
  886.                 { $$ = code_ptr ;
  887.                   code2(F_PUSHA, &field[0]) ; 
  888.                 }
  889.  
  890.             |   COMMA fvalue  RPAREN
  891.                 { $$ = $2 ; }
  892.             ;
  893.  
  894. /*================================================
  895.     user defined functions
  896.  *=================================*/
  897.  
  898. function_def  :  funct_start  block
  899.                  { resize_fblock($1, code_ptr) ;
  900.                    code_ptr = main_code_ptr ;
  901.                    scope = SCOPE_MAIN ;
  902.                    active_funct = (FBLOCK *) 0 ;
  903.                    restore_ids() ;
  904.                  }
  905.               ;
  906.                    
  907.  
  908. funct_start   :  funct_head  LPAREN  f_arglist  RPAREN
  909.                  { eat_nl() ;
  910.                    scope = SCOPE_FUNCT ;
  911.                    active_funct = $1 ;
  912.                    main_code_ptr = code_ptr ;
  913.  
  914.                    if ( $1->nargs = $3 )
  915.                         $1->typev = (char *) memset(
  916.                                zmalloc($3), ST_LOCAL_NONE, $3) ;
  917.                    else $1->typev = (char *) 0 ;
  918.                    code_ptr = $1->code = 
  919.                        (INST *) zmalloc(PAGE_SZ*sizeof(INST)) ;
  920.                  }
  921.               ;
  922.                   
  923. funct_head    :  FUNCTION  ID
  924.                  { FBLOCK  *fbp ;
  925.  
  926.                    if ( $2->type == ST_NONE )
  927.                    {
  928.                          $2->type = ST_FUNCT ;
  929.                          fbp = $2->stval.fbp = 
  930.                              (FBLOCK *) zmalloc(sizeof(FBLOCK)) ;
  931.                          fbp->name = $2->name ;
  932.                    }
  933.                    else
  934.                    {
  935.                          type_error( $2 ) ;
  936.  
  937.                          /* this FBLOCK will not be put in
  938.                             the symbol table */
  939.                          fbp = (FBLOCK*) zmalloc(sizeof(FBLOCK)) ;
  940.                          fbp->name = "" ;
  941.                    }
  942.                    $$ = fbp ;
  943.                  }
  944.  
  945.               |  FUNCTION  FUNCT_ID
  946.                  { $$ = $2 ; 
  947.                    if ( $2->code ) 
  948.                        compile_error("redefinition of %s" , $2->name) ;
  949.                  }
  950.               ;
  951.                          
  952. f_arglist  :  /* empty */ { $$ = 0 ; }
  953.            |  f_args
  954.            ;
  955.  
  956. f_args     :  ID
  957.               { $1 = save_id($1->name) ;
  958.                 $1->type = ST_LOCAL_NONE ;
  959.                 $1->offset = 0 ;
  960.                 $$ = 1 ;
  961.               }
  962.            |  f_args  COMMA  ID
  963.               { if ( is_local($3) ) 
  964.                   compile_error("%s is duplicated in argument list",
  965.                     $3->name) ;
  966.                 else
  967.                 { $3 = save_id($3->name) ;
  968.                   $3->type = ST_LOCAL_NONE ;
  969.                   $3->offset = $1 ;
  970.                   $$ = $1 + 1 ;
  971.                 }
  972.               }
  973.            ;
  974.  
  975. /* a call to a user defined function */
  976.              
  977. p_expr  :  FUNCT_ID mark  call_args
  978.            { $$ = $2 ;
  979.              code2(_CALL, $1) ;
  980.  
  981.              if ( $3 )  code1($3->arg_num+1) ;
  982.              else  code1(0) ;
  983.                
  984.              check_fcall($1, scope, active_funct, 
  985.                          $3, token_lineno) ;
  986.            }
  987.         ;
  988.  
  989. call_args  :   LPAREN   RPAREN
  990.                { $$ = (CA_REC *) 0 ; }
  991.            |   ca_front  ca_back
  992.                { $$ = $2 ;
  993.                  $$->link = $1 ;
  994.                  $$->arg_num = $1 ? $1->arg_num+1 : 0 ;
  995.                }
  996.            ;
  997.  
  998. /* The funny definition of ca_front with the COMMA bound to the ID is to
  999.    force a shift to avoid a reduce/reduce conflict
  1000.    ID->id or ID->array
  1001.  
  1002.    Or to avoid a decision, if the type of the ID has not yet been
  1003.    determined
  1004. */
  1005.  
  1006. ca_front   :  LPAREN
  1007.               { $$ = (CA_REC *) 0 ; }
  1008.            |  ca_front  expr   COMMA
  1009.               { $$ = (CA_REC *) zmalloc(sizeof(CA_REC)) ;
  1010.                 $$->link = $1 ;
  1011.                 $$->type = CA_EXPR  ;
  1012.                 $$->arg_num = $1 ? $1->arg_num+1 : 0 ;
  1013.               }
  1014.            |  ca_front  ID   COMMA
  1015.               { $$ = (CA_REC *) zmalloc(sizeof(CA_REC)) ;
  1016.                 $$->link = $1 ;
  1017.                 $$->arg_num = $1 ? $1->arg_num+1 : 0 ;
  1018.  
  1019.                 code_call_id($$, $2) ;
  1020.               }
  1021.            ;
  1022.  
  1023. ca_back    :  expr   RPAREN
  1024.               { $$ = (CA_REC *) zmalloc(sizeof(CA_REC)) ;
  1025.                 $$->type = CA_EXPR ;
  1026.               }
  1027.  
  1028.            |  ID    RPAREN
  1029.               { $$ = (CA_REC *) zmalloc(sizeof(CA_REC)) ;
  1030.                 code_call_id($$, $1) ;
  1031.               }
  1032.            ;
  1033.  
  1034.  
  1035.     
  1036.  
  1037. %%
  1038.  
  1039. /* resize the code for a user function */
  1040.  
  1041. static void  resize_fblock( fbp, code_ptr )
  1042.   FBLOCK *fbp ;
  1043.   INST *code_ptr ;
  1044. { int size ;
  1045.  
  1046.   code1(_RET0) ; /* make sure there is always a return statement */
  1047.  
  1048.   if ( dump_code )  
  1049.   { code1(_HALT) ; /*stops da() */
  1050.     add_to_fdump_list(fbp) ;
  1051.   }
  1052.  
  1053.   if ( (size = code_ptr - fbp->code) > PAGE_SZ-1 )
  1054.         overflow("function code size", PAGE_SZ ) ;
  1055.  
  1056.   /* resize the code */
  1057.   fbp->code = (INST*) zrealloc(fbp->code, PAGE_SZ*sizeof(INST),
  1058.                        size * sizeof(INST) ) ;
  1059.  
  1060. }
  1061.  
  1062. static void check_id( p )
  1063.   register SYMTAB *p ;
  1064. {
  1065.       switch(p->type)
  1066.       {
  1067.         case ST_NONE : /* new id */
  1068.             p->type = ST_VAR ;
  1069.             p->stval.cp = new_CELL() ;
  1070.             p->stval.cp->type = C_NOINIT ;
  1071.             break ;
  1072.  
  1073.         case ST_LOCAL_NONE :
  1074.             p->type = ST_LOCAL_VAR ;
  1075.             active_funct->typev[p->offset] = ST_LOCAL_VAR ;
  1076.             break ;
  1077.  
  1078.         case ST_VAR :
  1079.         case ST_LOCAL_VAR :  break ;
  1080.  
  1081.         default :
  1082.             type_error(p) ;
  1083.             break ;
  1084.       }
  1085. }
  1086.  
  1087. static  void  check_array(p)
  1088.   register SYMTAB *p ;
  1089. {
  1090.       switch(p->type)
  1091.       {
  1092.         case ST_NONE :  /* a new array */
  1093.             p->type = ST_ARRAY ;
  1094.             p->stval.array = new_ARRAY() ;
  1095.             break ;
  1096.  
  1097.         case  ST_ARRAY :
  1098.         case  ST_LOCAL_ARRAY :
  1099.             break ;
  1100.  
  1101.         case  ST_LOCAL_NONE  :
  1102.             p->type = ST_LOCAL_ARRAY ;
  1103.             active_funct->typev[p->offset] = ST_LOCAL_ARRAY ;
  1104.             break ;
  1105.  
  1106.         default : type_error(p) ; break ;
  1107.       }
  1108. }
  1109.  
  1110. static void code_array(p)
  1111.   register SYMTAB *p ;
  1112. { if ( is_local(p) )
  1113.   { code1(LA_PUSHA) ; code1(p->offset) ; }
  1114.   else  code2(A_PUSHA, p->stval.array) ;
  1115. }
  1116.  
  1117. static  void  field_A2I()
  1118. {
  1119.      if ( code_ptr[-2].op == F_PUSHA )
  1120.            code_ptr[-2].op =  
  1121.                ((CELL *)code_ptr[-1].ptr == field ||
  1122.                 (CELL *)code_ptr[-1].ptr >  field+NF )
  1123.                 ? _PUSHI : F_PUSHI ;
  1124.      else if ( code_ptr[-1].op == FE_PUSHA ) 
  1125.            code_ptr[-1].op = FE_PUSHI ;
  1126.      else  bozo("missing F(E)_PUSHA") ;
  1127. }
  1128.  
  1129. static  int  current_offset()
  1130. {
  1131.   switch( scope )
  1132.   { 
  1133.     case  SCOPE_MAIN :  return code_ptr - main_start ;
  1134.     case  SCOPE_BEGIN :  return code_ptr - begin_start ;
  1135.     case  SCOPE_END   :  return code_ptr - end_start ;
  1136.     case  SCOPE_FUNCT :  return code_ptr - active_funct->code ;
  1137.   }
  1138. }
  1139.  
  1140. static void  code_call_id( p, ip )
  1141.   register CA_REC *p ;
  1142.   register SYMTAB *ip ;
  1143. { static CELL dummy ;
  1144.  
  1145.   switch( ip->type )
  1146.   {
  1147.     case  ST_VAR  :
  1148.             p->type = CA_EXPR ;
  1149.             code2(_PUSHI, ip->stval.cp) ;
  1150.             break ;
  1151.  
  1152.     case  ST_LOCAL_VAR  :
  1153.             p->type = CA_EXPR ;
  1154.             code1(L_PUSHI) ;
  1155.             code1(ip->offset) ;
  1156.             break ;
  1157.  
  1158.     case  ST_ARRAY  :
  1159.             p->type = CA_ARRAY ;
  1160.             code2(A_PUSHA, ip->stval.array) ;
  1161.             break ;
  1162.  
  1163.     case  ST_LOCAL_ARRAY :
  1164.             p->type = CA_ARRAY ;
  1165.             code1(LA_PUSHA) ;
  1166.             code1(ip->offset) ;
  1167.             break ;
  1168.  
  1169.     case  ST_NONE :
  1170.             p->type = ST_NONE ;
  1171.             p->call_offset = current_offset() ;
  1172.             p->sym_p = ip ;
  1173.             code2(_PUSHI, &dummy) ;
  1174.             break ;
  1175.  
  1176.     case  ST_LOCAL_NONE :
  1177.             p->type = ST_LOCAL_NONE ;
  1178.             p->call_offset = current_offset() ;
  1179.             p->type_p = & active_funct->typev[ip->offset] ;
  1180.             code1(L_PUSHI) ; 
  1181.             code1(ip->offset) ;
  1182.             break ;
  1183.  
  1184.   
  1185. #ifdef   DEBUG
  1186.     default :
  1187.             bozo("code_call_id") ;
  1188. #endif
  1189.  
  1190.   }
  1191. }
  1192.  
  1193. int parse()
  1194. { int yy = yyparse() ;
  1195.  
  1196. #if  YYBYACC
  1197.   extern struct yacc_mem *yacc_memp ;
  1198.  
  1199.   yacc_memp++  ; /* puts parser tables in mem pool */
  1200. #endif
  1201.  
  1202.   if ( resolve_list )  resolve_fcalls() ;
  1203.   return yy ;
  1204. }
  1205.  
  1206.